/*
 * search_thread.cpp
 *
 *  Created on: 23.06.2013
 *      Author: SpirTanol
 */

#include "device/search_thread.h"
#include "packets/search_packet.h"
#include "device/device_info.h"
#include "events/search_event.h"

// ModbusLib
#include "modbus.h"

// QT
#include <QMetaType>
#include <QDebug>
//=================================================================================================
SearchThread::SearchThread(QObject *parent) : QThread(parent), oMPort(0), oDestroyed(false)
{
	qRegisterMetaType<SearchEvent*>("SearchEvent*");
	connect(this, SIGNAL(terminated()), this, SLOT(stoped()));
	connect(this, SIGNAL(finished()), this, SLOT(searchFinished()));
	reset();
}

SearchThread::~SearchThread()
{
	oDestroyed = true;
	wait();
}
//=================================================================================================
void SearchThread::run()
{
	oMPort = new ModbusPort(ModbusPort::RTU, QString("\\\\.\\COM%1").arg(oPort).toAscii().data());
	SearchPacket packet;

	if (!oMPort->open())
	{
		emit searchEvent(new SearchEventError(SearchEventError::OPEN_ERROR));
		return;
	}

	emit searchEvent(new SearchEvent(SET_STARTED));

	oMPort->setTimeout(getTimeout(oSpeed));
	oMPort->setSpeed(oSpeed);

	// Добавление одного устройства
	if (oOneTest)
	{
		oMPort->setAddr(oOneAddr);
		oMPort->setFormat(oOneFormat);
		if(readPacket(&packet))
		{
			DeviceInfo *inf = createDevice(packet);
			inf->setAddr(oOneAddr);
			inf->setFormat(oOneFormat);
			inf->setSpeed(oSpeed);
			inf->setPort(oPort);
			emit searchEvent(new SearchEventFound(inf));
		}

		emit searchEvent(new SearchEvent(SET_TEST_FINISHED));
		return;
	}

	extern const int gFormats[];

	for (; oAddr < 248; ++oAddr)
	{
		oMPort->setAddr(oAddr);
		for (; oFormat < 3; ++oFormat)
		{
			oMPort->setFormat(gFormats[oFormat]);
			if(readPacket(&packet))
			{
				DeviceInfo *inf = createDevice(packet);
				inf->setAddr(oAddr);
				inf->setFormat(gFormats[oFormat]);
				inf->setSpeed(oSpeed);
				inf->setPort(oPort);

				emit searchEvent(new SearchEventFound(inf));
			}
			if (oDestroyed) return;
			++oStep;
			emit searchEvent(new SearchEvent(SET_STEP));
		}
		oFormat = 0;
	}

	emit searchEvent(new SearchEvent(SET_FINISHED));
}
//=================================================================================================
void SearchThread::reset()
{
	oFormat = 0;
	oAddr = 1;
	oStep = 0;
}
//=================================================================================================
void SearchThread::startSearch()
{
	oOneTest = false;

	reset();
	start();
}

void SearchThread::stopSearch()
{
	if (!isRunning()) return;

	terminate();
	wait();

	oOneTest = false;
}

void SearchThread::toggleSearch()
{
	oOneTest = false;

	if (isRunning())
		stopSearch();
	else
		start();
}
//=================================================================================================
void SearchThread::stoped()
{
	emit searchEvent(new SearchEvent(SET_STOPED));
}
//=================================================================================================
void SearchThread::searchFinished()
{
	if (oMPort)
	{
		oMPort->close();
		delete oMPort;
		oMPort = 0;
	}
}
//=================================================================================================
void SearchThread::oneTest(int addr, int format)
{
	oOneTest = true;
	oOneAddr = addr;
	oOneFormat = format;

	start();
}
//=================================================================================================
DeviceInfo *SearchThread::createDevice(const SearchPacket &packet)
{
	DeviceInfo *inf = new DeviceInfo();
	if (((packet.curMin() == 50 && packet.scale() == 1) || packet.curMin() == 10 || packet.curMin() == 84) && packet.curMin() * 10 == packet.curMax())
	{
		inf->setCurrentInfo(packet.scale(), float(packet.curMin()) / float(packet.scale()),
				float(packet.curMax()) / float(packet.scale()));
		inf->setVersion(packet.version());
		inf->setType(DT_DPE11);
	}
	else
		inf->setType(DT_UNKOWN);

	return inf;
}
//=================================================================================================
bool SearchThread::readPacket(DataPacket *packet)
{
	bool suc = true;
	int count = packet->partCount();
	for (int i = 0; i < count && suc; ++i)
	{
		const DataPacket::Part &part = packet->part(i);
		suc = oMPort->readHoldingRegisters(part.oPtr, part.oAddr, part.oSize);
	}

	return suc;
}
//=================================================================================================
